import { History } from '@/common/history'
import { eventBus, useEventBus } from '@/widgets'
import type { LngLat } from '@/geom/great-circle'
import {
  centerOfMapFeatures,
  overlay,
  setMapCenter,
  setMapCenterIfNotContain,
  type MapFeatures
} from '@/map'
import type { MapItemInfo } from '../types'
import { getMapItemTypeSpec, type MapItemOptions, type MapItemTypeSpec } from '../base'

export const history = new History<MapItemInfo<any>>(100)
export let selected: MapItemInfo<any> | null = null
export let selectedCenter: LngLat | null = null

const selectedChangedEvent = Symbol('map-item-selected-changed')

export function unSelectMapItem() {
  if (!selected) {
    return
  }
  selected = null
  onSelectedChanged(false)
}

export function selectMapItem<T>(type: string, item: T, locate: boolean = false) {
  const spec = getMapItemTypeSpec(type)
  if (!spec) {
    return
  }
  const info = {
    type,
    typeName: spec.typeName,
    icon: spec.icon,
    name: spec.getName(item),
    item
  }
  history.push(info)
  selected = info
  onSelectedChanged(locate)
}

export function selectBack(locate: boolean = true) {
  const info = history.back()
  if (!info) {
    return
  }
  selected = info
  onSelectedChanged(locate)
}

export function selectForward(locate: boolean = true) {
  const info = history.forward()
  if (!info) {
    return
  }
  selected = info
  onSelectedChanged(locate)
}

export function locateSelected() {
  if (!selectedCenter) {
    return
  }
  setMapCenter(selectedCenter)
}

function onSelectedChanged(locate: boolean) {
  if (!selected) {
    eventBus.emit(selectedChangedEvent, selected)
    overlay.clear()
    return
  }
  const spec = getMapItemTypeSpec(selected.type)
  const fs = highlightOnOverlay(spec as MapItemTypeSpec<any>, selected.item)
  if (!fs) {
    selectedCenter = null
  } else {
    selectedCenter = centerOfMapFeatures(fs)
    if (locate && selectedCenter) {
      setMapCenterIfNotContain(selectedCenter)
    }
  }
  eventBus.emit(selectedChangedEvent, selected)
}

export function useListenMapItemSelected(callback: (e: MapItemInfo<any> | null) => void) {
  useEventBus(selectedChangedEvent, callback)
}

function highlightOnOverlay(opts: MapItemTypeSpec<any>, item: any): MapFeatures | null {
  const { highlight } = opts
  if (!highlight) {
    overlay.clear()
    return null
  }
  const f = highlight(item)
  if (!f) {
    overlay.clear()
    return null
  }
  overlay.update(f)
  return f
}
